# -*- python -*-
# ex: set syntax=python:
# Copyright (c) 2012 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.

# READ THIS:
# See http://dev.chromium.org/developers/testing/chromium-build-infrastructure

import os
import socket

from buildbot.scheduler import Triggerable
from buildbot.scheduler import Nightly

# These modules come from scripts, which must be in the PYTHONPATH.
from master import master_utils
from master import slaves_list
from master.builders_pools import BuildersPools
from master.factory import annotator_factory
from master.factory import remote_run_factory
from master.try_job_http import TryJobHTTP

import config
import master_site_config

ActiveMaster = master_site_config.TryServerChromiumWin


MAIL_NOTIFIER = ActiveMaster.is_production_host

m_annotator = annotator_factory.AnnotatorFactory(ActiveMaster)

# This is the dictionary that the buildmaster pays attention to. We also use
# a shorter alias to save typing.
c = BuildmasterConfig = {}

config.DatabaseSetup(c)

####### CHANGESOURCES

c['change_source'] = []

# Avoid merging requests.
c['mergeRequests'] = False


####### BUILDERS

# Try queues.
pools = BuildersPools('chrome')

chromium_builders = []

def base_factory(recipe, factory_properties=None, **kwargs):
  fp = factory_properties or {}
  return m_annotator.BaseFactory(recipe, factory_properties=fp, **kwargs)


def m_remote_run(recipe, **kwargs):
  return remote_run_factory.RemoteRunFactory(
      active_master=ActiveMaster,
      repository='https://chromium.googlesource.com/chromium/tools/build.git',
      recipe=recipe,
      factory_properties={'path_config': 'kitchen'},
      **kwargs)


for targ in ('_rel', '_dbg'):
  chromium_builders.extend([{
    'name': 'win_chromium%s_ng' % targ,
    'factory': m_remote_run(
        'chromium_trybot', timeout=3600, max_time=master_utils.CQ_MAX_TIME),
    'slavebuilddir': 'remote_run'
  }, {
    'name': 'win_chromium_compile%s_ng' % targ,
    'factory': m_remote_run(
        'chromium_trybot', timeout=3600, max_time=master_utils.CQ_MAX_TIME),
    'slavebuilddir': 'remote_run'
  }])

chromium_builders.append({
  'name': 'win10_chromium_x64_rel_ng',
  'factory': m_remote_run('chromium_trybot', timeout=3600),
  'slavebuilddir': 'remote_run',
})

chromium_builders.append({
  'name': 'win_archive',
  'factory': m_remote_run('chromium_trybot', timeout=3600),
  'slavebuilddir': 'remote_run',
})

chromium_builders.append({
  'name': 'win_x64_archive',
  'factory': m_remote_run('chromium_trybot', timeout=3600),
  'slavebuilddir': 'remote_run',
})

chromium_builders.append({
  'name': 'win_chromium_x64_rel_ng',
  'factory': m_remote_run(
      'chromium_trybot', timeout=3600, max_time=master_utils.CQ_MAX_TIME),
  'slavebuilddir': 'remote_run'
})

chromium_builders.extend([{
    'name': 'win8_chromium_gn_upload',
    'factory': base_factory('chromium_gn_upload'),
    'slavebuilddir': 'win_gn',
  },
])

chromium_builders.append({
  'name': 'win_upload_clang',
  'factory': base_factory('chromium_upload_clang'),
  'slavebuilddir': 'win_upload_clang',
})

chromium_builders.append({
    'name': 'win_pgo',
    'factory':  base_factory('chromium_pgo', timeout=24000),
    'slavebuilddir': 'win',
})

chromium_builders.append({
    'name': 'win_pgo_x64',
    'factory':  base_factory('chromium_pgo', timeout=28800),
    'slavebuilddir': 'win',
})

chromium_builders.append({
    'name': 'win_chrome_official',
    'factory': m_remote_run('chromium_trybot', timeout=4800),
    'slavebuilddir': 'remote_run',
})

chromium_builders.append({
  'name': 'win_chromium_syzyasan_rel',
  'factory': m_remote_run('chromium_trybot'),
  'slavebuilddir': 'remote_run',
})

# Experimental clang/win bots
chromium_builders.append({
  'name': 'win_clang',
  'factory': m_remote_run('chromium_trybot'),
  'slavebuilddir': 'remote_run',
})
chromium_builders.append({
  'name': 'win_clang_dbg',
  'factory': m_remote_run('chromium_trybot'),
  'slavebuilddir': 'remote_run',
})
chromium_builders.append({
  'name': 'win_clang_rel',
  'factory': m_remote_run('chromium_trybot'),
  'slavebuilddir': 'remote_run',
})
chromium_builders.append({
  'name': 'win_clang_x64_dbg',
  'factory': m_remote_run('chromium_trybot'),
  'slavebuilddir': 'remote_run',
})
chromium_builders.append({
  'name': 'win_clang_x64_rel',
  'factory': m_remote_run('chromium_trybot'),
  'slavebuilddir': 'remote_run',
})
chromium_builders.append({
  'name': 'win_mojo',
  'factory': m_remote_run('chromium_trybot'),
  'slavebuilddir': 'remote_run',
})

# Optional GPU tryserver.
chromium_builders.append({
  'name': 'win_optional_gpu_tests_rel',
  'factory': m_remote_run('chromium_trybot', timeout=3600),
  'slavebuilddir': 'remote_run'
})

# NaCl SDK try bots
b_win_nacl_sdk = {
  'name': 'win_nacl_sdk',
  'factory': base_factory('nacl/sdk'),
}

# NaCl SDK build-only try bots
b_win_nacl_sdk_build = {
  'name': 'win_nacl_sdk_build',
  'factory': base_factory('nacl/sdk_build'),
}

# These variable builders are used by Findit to identify culprit commits that
# introduce compile failures, reliable test failures, or test flakiness on the
# main waterfall. They run on optional slaves and NOT CQ slaves.
variable_builders = [
  {
    'name': 'win_chromium_variable',
    'factory': m_remote_run('findit/chromium/compile'),
    'slavebuilddir': 'win'
  },
  {
    'name': 'win_chromium_variable_deflake',
    'factory': m_remote_run('findit/chromium/flake'),
    'slavebuilddir': 'win'
  },
  {
    'name': 'win_chromium_variable_archive',
    'factory': m_remote_run('findit/chromium/compile'),
    'slavebuilddir': 'win_archive'
  },
  {
    'name': 'win_chromium_variable_chrome',
    'factory': m_remote_run('findit/chromium/compile'),
    'slavebuilddir': 'win_chrome'
  },
  {
    'name': 'win_chromium_variable_clang',
    'factory': m_remote_run('findit/chromium/compile'),
    'slavebuilddir': 'win'
  },
  {
    'name': 'win_chromium_variable_webkit_builder',
    'factory': m_remote_run('findit/chromium/compile'),
    'slavebuilddir': 'win_webkit'
  },
  {
    'name': 'win_chromium_variable_webkit_win7_builder',
    'factory': m_remote_run('findit/chromium/compile'),
    'slavebuilddir': 'win_webkit'
  },
  {
    'name': 'win_chromium_variable_webkit_win7_builder_x64',
    'factory': m_remote_run('findit/chromium/compile'),
    'slavebuilddir': 'win_webkit'
  },
  {
    'name': 'win_x64_chromium_variable_builder',
    'factory': m_remote_run('findit/chromium/compile'),
    'slavebuilddir': 'win'
  },
]

c['builders'] = [
  b_win_nacl_sdk,
  b_win_nacl_sdk_build,
] + chromium_builders + variable_builders


# Slaves are loaded from slaves.cfg.
slaves = slaves_list.SlavesList('slaves.cfg', 'TryServerChromiumWin')

for builder in c['builders']:
  # Associate the slaves to the builders. The configuration is in slaves.cfg.
  builder['slavenames'] = slaves.GetSlavesName(builder=builder['name'])
  # Sets nextSlave function for slave affinity.
  builder['nextSlave'] = master_utils.PreferredBuilderNextSlaveFunc()
  # Don't enable auto_reboot for people testing locally.
  builder.setdefault('auto_reboot', ActiveMaster.is_production_host)


####### BUILDSLAVES

# The 'slaves' list defines the set of allowable buildslaves. List all the
# slaves registered to a builder. Remove dupes.
c['slaves'] = master_utils.AutoSetupSlaves(
    c['builders'],
    config.Master.GetBotPassword(),
    preferred_builder_dict=slaves.GetPreferredBuildersDict())

# Make sure everything works together.
master_utils.VerifySetup(c, slaves)


####### SCHEDULERS

# Configure the Schedulers;
# Main Tryscheduler for the try queue. groups is defined in the loop above.
c['schedulers'] = []

last_good_urls = {'chrome': ActiveMaster.last_good_url,
                  'blink': ActiveMaster.last_good_blink_url}
code_review_sites = {'chrome': ActiveMaster.code_review_site,
                     'blink': ActiveMaster.code_review_site}

c['schedulers'].append(TryJobHTTP(
      name='try_job_http',
      port=ActiveMaster.try_job_port,
      last_good_urls=last_good_urls,
      code_review_sites=code_review_sites,
      pools=pools))

####### PREEMPTIVE UPDATER
updater_builders = [
  'win_chromium_variable',
]
for target_builder in updater_builders:
  variable_slaves_count = len(slaves.GetSlavesName(builder=target_builder))
  # Add one scheduler per slave to run this lightweight task hourly.
  for i in range(variable_slaves_count):
    c['schedulers'].append(
      Nightly(
        name='preemptive_updater_%s_%d' % (target_builder, i),
        branch=None,
        builderNames=[target_builder],
        minute=[15],
        properties={'recipe': 'findit/chromium/preemptive_bot_update'},
      )
    )

####### STATUS TARGETS

# Buildbot master url:
# Must come before AutoSetupMaster().
if ActiveMaster.is_production_host:
  c['buildbotURL'] = ActiveMaster.buildbot_url
else:
  c['buildbotURL'] = 'http://%s:%d/' % (
      socket.getfqdn(), ActiveMaster.master_port)

# Adds common status and tools to this master.
master_utils.AutoSetupMaster(
    c, ActiveMaster,
    public_html='../master.tryserver.chromium.linux/public_html',
    templates=['../master.tryserver.chromium.linux/templates'])

if MAIL_NOTIFIER:
  # Add a dumb MailNotifier first so it will be used for BuildSlave with
  # notify_on_missing set when they go missing.
  from buildbot.status import mail
  c['status'].append(mail.MailNotifier(
      fromaddr=ActiveMaster.from_address,
      builders=[],
      relayhost=config.Master.smtp,
      lookup=master_utils.UsersAreEmails()))

  # Try job result emails.
  from master.try_mail_notifier import TryMailNotifier
  c['status'].append(TryMailNotifier(
      fromaddr=ActiveMaster.from_address,
      reply_to=ActiveMaster.reply_to,
      subject="try %(result)s for %(reason)s @ r%(revision)s",
      mode='all',
      relayhost=config.Master.smtp,
      lookup=master_utils.UsersAreEmails(),
      # disable success emails from triggered builders
      no_email_on_success=['android_dbg', 'android_dbg_recipe',
                           'android_fyi_dbg', 'android_rel',
                           'linux_arm_cross_compile']))


# The followings are what is kept on disk.
# Keep last try jobs, the default is too low. Must keep at least a few days
# worth of try jobs. 3000 is not even a full day but the server is full. Keep
# more build objects than log since they are much smaller.
c['buildHorizon'] = 6000
c['logHorizon'] = 3000
# Must be at least 2x the number of slaves.
c['eventHorizon'] = 200

# Adjust the buildCaches to be 3x the number of slaves per builder.
c['autoBuildCacheRatio'] = 3


# Hack buildbot so the Stop build button doesn't work anymore. Otherwise it's
# just a pain, user misuse this button all the time.
def hack_stop(function):
  def hook(*args, **kwargs):
    result = function(*args, **kwargs)
    result = result.replace('<input type="submit" value="Stop',
        '<input type="button" onclick="alert(\''
        'For more information, visit '
        'http://dev.chromium.org/developers/try-server-usage'
        '\');"'
        ' value="Stop')
    return result
  return hook

# Only do the hack_stop if we are the production master.  This allows
# us to keep the STOP button live for local/test instances.
#if ActiveMaster.is_production_host:
#  from buildbot.status.web.builder import StatusResourceBuilder
#  StatusResourceBuilder.build_line = hack_stop(StatusResourceBuilder.build_line)
#  from buildbot.status.web import base
#  base.make_stop_form = hack_stop(base.make_stop_form)


####### PROJECT IDENTITY

# The 'projectURL' string will be used to provide a link
# from buildbot HTML pages to your project's home page.
c['projectURL'] = 'http://dev.chromium.org/developers/testing/try-server-usage'

# vi: set ts=4 sts=2 sw=2 et:
